<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Graph Convolutional Networks &mdash; Graph4NLP v0.4.1 documentation</title><link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" />
    <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
  <!--[if lt IE 9]>
    <script src="../../_static/js/html5shiv.min.js"></script>
  <![endif]-->
  <script id="documentation_options" data-url_root="../../" src="../../_static/documentation_options.js"></script>
        <script src="../../_static/jquery.js"></script>
        <script src="../../_static/underscore.js"></script>
        <script src="../../_static/doctools.js"></script>
        <script src="../../_static/language_data.js"></script>
        <script async="async" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js?config=TeX-AMS-MML_HTMLorMML"></script>
    <script src="../../_static/js/theme.js"></script>
    <link rel="index" title="Index" href="../../genindex.html" />
    <link rel="search" title="Search" href="../../search.html" />
    <link rel="next" title="Gated Graph Neural Networks" href="ggnn.html" />
    <link rel="prev" title="Chapter 4. Graph Encoder" href="../gnn.html" /> 
</head>

<body class="wy-body-for-nav"> 
  <div class="wy-grid-for-nav">
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-scroll">
        <div class="wy-side-nav-search" >
            <a href="../../index.html" class="icon icon-home"> Graph4NLP
          </a>
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>
        </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
              <p class="caption"><span class="caption-text">Get Started</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../welcome/installation.html">Install Graph4NLP</a></li>
</ul>
<p class="caption"><span class="caption-text">User Guide</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../graphdata.html">Chapter 1. Graph Data</a></li>
<li class="toctree-l1"><a class="reference internal" href="../dataset.html">Chapter 2. Dataset</a></li>
<li class="toctree-l1"><a class="reference internal" href="../construction.html">Chapter 3. Graph Construction</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="../gnn.html">Chapter 4. Graph Encoder</a><ul class="current">
<li class="toctree-l2 current"><a class="current reference internal" href="#">Graph Convolutional Networks</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#gcn-module-construction-function">4.1.1 GCN Module Construction Function</a></li>
<li class="toctree-l3"><a class="reference internal" href="#gcnlayer-construction-function">4.1.2 GCNLayer Construction Function</a></li>
<li class="toctree-l3"><a class="reference internal" href="#gcnlayerconv-construction-function">4.1.3 GCNLayerConv Construction Function</a></li>
<li class="toctree-l3"><a class="reference internal" href="#gcn-forward-function">4.1.4 GCN Forward Function</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="ggnn.html">Gated Graph Neural Networks</a></li>
<li class="toctree-l2"><a class="reference internal" href="gat.html">Graph Attention Networks</a></li>
<li class="toctree-l2"><a class="reference internal" href="graphsage.html">GraphSAGE</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../decoding.html">Chapter 5. Decoder</a></li>
<li class="toctree-l1"><a class="reference internal" href="../classification.html">Chapter 6. Classification</a></li>
<li class="toctree-l1"><a class="reference internal" href="../evaluation.html">Chapter 7. Evaluations and Loss components</a></li>
</ul>
<p class="caption"><span class="caption-text">Module API references</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../modules/data.html">graph4nlp.data</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../modules/datasets.html">graph4nlp.datasets</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../modules/graph_construction.html">graph4nlp.graph_construction</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../modules/graph_embedding.html">graph4nlp.graph_embedding</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../modules/prediction.html">graph4nlp.prediction</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../modules/loss.html">graph4nlp.loss</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../modules/evaluation.html">graph4nlp.evaluation</a></li>
</ul>
<p class="caption"><span class="caption-text">Tutorials</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../tutorial/text_classification.html">Text Classification Tutorial</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../tutorial/semantic_parsing.html">Semantic Parsing Tutorial</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../tutorial/math_word_problem.html">Math Word Problem Tutorial</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../tutorial/knowledge_graph_completion.html">Knowledge Graph Completion Tutorial</a></li>
</ul>

        </div>
      </div>
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
          <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
          <a href="../../index.html">Graph4NLP</a>
      </nav>

      <div class="wy-nav-content">
        <div class="rst-content">
          <div role="navigation" aria-label="Page navigation">
  <ul class="wy-breadcrumbs">
      <li><a href="../../index.html" class="icon icon-home"></a> &raquo;</li>
          <li><a href="../gnn.html">Chapter 4. Graph Encoder</a> &raquo;</li>
      <li>Graph Convolutional Networks</li>
      <li class="wy-breadcrumbs-aside">
            <a href="../../_sources/guide/gnn/gcn.rst.txt" rel="nofollow"> View page source</a>
      </li>
  </ul>
  <hr/>
</div>
          <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
           <div itemprop="articleBody">
             
  <div class="section" id="graph-convolutional-networks">
<span id="guide-gcn"></span><h1>Graph Convolutional Networks<a class="headerlink" href="#graph-convolutional-networks" title="Permalink to this headline">¶</a></h1>
<p>Graph Convolutional Networks (<a class="reference external" href="https://arxiv.org/abs/1609.02907">GCN</a>) is a typical example of spectral-based graph filters.
A multi-layer GCN is considered with the following layer-wise propagation rule using spectral graph theory:</p>
<div class="math notranslate nohighlight">
\[\mathbf{H}^{(l)} = \sigma( {\tilde{D}}^{-\frac{1}{2}}{\tilde{A}}{\tilde{D}}^{-\frac{1}{2}} \mathbf{H}^{(l-1)} \mathbf{W}^{(l-1)})\]</div>
<p>Here, <span class="math notranslate nohighlight">\(\mathbf{W}^{(l-1)}\)</span> is a layer-specific trainable weight matrix and
<span class="math notranslate nohighlight">\(\sigma(\cdot)\)</span> denotes an activation function.
<span class="math notranslate nohighlight">\(\mathbf{H}^{(l)} \in \mathbb{R}^{n \times d}\)</span> is the activated node embeddings
at <span class="math notranslate nohighlight">\((l-1)\)</span>-th layer.</p>
<div class="section" id="gcn-module-construction-function">
<h2>4.1.1 GCN Module Construction Function<a class="headerlink" href="#gcn-module-construction-function" title="Permalink to this headline">¶</a></h2>
<p>The construction function performs the following steps:</p>
<ol class="arabic simple">
<li><p>Set options.</p></li>
<li><p>Register learnable parameters or submodules (<code class="docutils literal notranslate"><span class="pre">GCNLayer</span></code>).</p></li>
</ol>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">GCN</span><span class="p">(</span><span class="n">GNNBase</span><span class="p">):</span>
        <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span>
                     <span class="n">num_layers</span><span class="p">,</span>
                     <span class="n">input_size</span><span class="p">,</span>
                     <span class="n">hidden_size</span><span class="p">,</span>
                     <span class="n">output_size</span><span class="p">,</span>
                     <span class="n">direction_option</span><span class="o">=</span><span class="s1">&#39;bi_sep&#39;</span><span class="p">,</span>
                     <span class="n">feat_drop</span><span class="o">=</span><span class="mf">0.</span><span class="p">,</span>
                     <span class="n">gcn_norm</span><span class="o">=</span><span class="s1">&#39;both&#39;</span><span class="p">,</span>
                     <span class="n">weight</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
                     <span class="n">bias</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
                     <span class="n">activation</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
                     <span class="n">allow_zero_in_degree</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
                     <span class="n">use_edge_weight</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
                     <span class="n">residual</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
            <span class="nb">super</span><span class="p">(</span><span class="n">GCN</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">num_layers</span> <span class="o">=</span> <span class="n">num_layers</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">direction_option</span> <span class="o">=</span> <span class="n">direction_option</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">gcn_layers</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">ModuleList</span><span class="p">()</span>
            <span class="k">assert</span> <span class="bp">self</span><span class="o">.</span><span class="n">num_layers</span> <span class="o">&gt;</span> <span class="mi">0</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">use_edge_weight</span> <span class="o">=</span> <span class="n">use_edge_weight</span>

            <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">hidden_size</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
                <span class="n">hidden_size</span> <span class="o">=</span> <span class="p">[</span><span class="n">hidden_size</span><span class="p">]</span> <span class="o">*</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">num_layers</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>

            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">num_layers</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
                <span class="c1"># input projection</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">gcn_layers</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">GCNLayer</span><span class="p">(</span><span class="n">input_size</span><span class="p">,</span>
                                                <span class="n">hidden_size</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
                                                <span class="n">direction_option</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">direction_option</span><span class="p">,</span>
                                                <span class="n">feat_drop</span><span class="o">=</span><span class="n">feat_drop</span><span class="p">,</span>
                                                <span class="n">gcn_norm</span><span class="o">=</span><span class="n">gcn_norm</span><span class="p">,</span>
                                                <span class="n">weight</span><span class="o">=</span><span class="n">weight</span><span class="p">,</span>
                                                <span class="n">bias</span><span class="o">=</span><span class="n">bias</span><span class="p">,</span>
                                                <span class="n">activation</span><span class="o">=</span><span class="n">activation</span><span class="p">,</span>
                                                <span class="n">allow_zero_in_degree</span><span class="o">=</span><span class="n">allow_zero_in_degree</span><span class="p">,</span>
                                                <span class="n">residual</span><span class="o">=</span><span class="n">residual</span><span class="p">))</span>

            <span class="c1"># hidden layers</span>
            <span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">num_layers</span> <span class="o">-</span> <span class="mi">1</span><span class="p">):</span>
                <span class="c1"># due to multi-head, the input_size = hidden_size * num_heads</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">gcn_layers</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">GCNLayer</span><span class="p">(</span><span class="n">hidden_size</span><span class="p">[</span><span class="n">l</span> <span class="o">-</span> <span class="mi">1</span><span class="p">],</span>
                                                <span class="n">hidden_size</span><span class="p">[</span><span class="n">l</span><span class="p">],</span>
                                                <span class="n">direction_option</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">direction_option</span><span class="p">,</span>
                                                <span class="n">feat_drop</span><span class="o">=</span><span class="n">feat_drop</span><span class="p">,</span>
                                                <span class="n">gcn_norm</span><span class="o">=</span><span class="n">gcn_norm</span><span class="p">,</span>
                                                <span class="n">weight</span><span class="o">=</span><span class="n">weight</span><span class="p">,</span>
                                                <span class="n">bias</span><span class="o">=</span><span class="n">bias</span><span class="p">,</span>
                                                <span class="n">activation</span><span class="o">=</span><span class="n">activation</span><span class="p">,</span>
                                                <span class="n">allow_zero_in_degree</span><span class="o">=</span><span class="n">allow_zero_in_degree</span><span class="p">,</span>
                                                <span class="n">residual</span><span class="o">=</span><span class="n">residual</span><span class="p">))</span>
            <span class="c1"># output projection</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">gcn_layers</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">GCNLayer</span><span class="p">(</span><span class="n">hidden_size</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">num_layers</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="k">else</span> <span class="n">input_size</span><span class="p">,</span>
                                            <span class="n">output_size</span><span class="p">,</span>
                                            <span class="n">direction_option</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">direction_option</span><span class="p">,</span>
                                            <span class="n">feat_drop</span><span class="o">=</span><span class="n">feat_drop</span><span class="p">,</span>
                                            <span class="n">gcn_norm</span><span class="o">=</span><span class="n">gcn_norm</span><span class="p">,</span>
                                            <span class="n">weight</span><span class="o">=</span><span class="n">weight</span><span class="p">,</span>
                                            <span class="n">bias</span><span class="o">=</span><span class="n">bias</span><span class="p">,</span>
                                            <span class="n">activation</span><span class="o">=</span><span class="n">activation</span><span class="p">,</span>
                                            <span class="n">allow_zero_in_degree</span><span class="o">=</span><span class="n">allow_zero_in_degree</span><span class="p">,</span>
                                            <span class="n">residual</span><span class="o">=</span><span class="n">residual</span><span class="p">))</span>
</pre></div>
</div>
<p>In construction function, one first needs to set the number of GCN layers and the data dimensions. For
general PyTorch module, the dimensions are usually input dimension,
output dimension and hidden dimension.</p>
<p>Besides data dimensions, a typical option for graph neural network is
direction option (<code class="docutils literal notranslate"><span class="pre">self.direction_option</span></code>). Direction option determines whether to use unidirectional (i.e., <code class="docutils literal notranslate"><span class="pre">undirected</span></code>) or bidirectional (i.e., <code class="docutils literal notranslate"><span class="pre">bi_sep</span></code> and <code class="docutils literal notranslate"><span class="pre">bi_fuse</span></code>) version of GCN.</p>
<p><code class="docutils literal notranslate"><span class="pre">gcn_norm</span></code> here is a callable function for feature normalization. In the
GCN paper, such normalization can be: <code class="docutils literal notranslate"><span class="pre">right</span></code>, <code class="docutils literal notranslate"><span class="pre">both</span></code>,
<code class="docutils literal notranslate"><span class="pre">none</span></code>.</p>
<p><code class="docutils literal notranslate"><span class="pre">use_edge_weight</span></code> represents whether to use edge weights when computing the node embeddings.</p>
<p><code class="docutils literal notranslate"><span class="pre">residual</span></code> represents whether to add residual connection between different GCN layers.</p>
</div>
<div class="section" id="gcnlayer-construction-function">
<h2>4.1.2 GCNLayer Construction Function<a class="headerlink" href="#gcnlayer-construction-function" title="Permalink to this headline">¶</a></h2>
<p><code class="docutils literal notranslate"><span class="pre">GCNLayer</span></code> is a single-layer GCN and its initial options are same as class <code class="docutils literal notranslate"><span class="pre">GCN</span></code>.
This module registers different GCNLayerConv according to <code class="docutils literal notranslate"><span class="pre">direction_option</span></code>.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">GCNLayer</span><span class="p">(</span><span class="n">GNNLayerBase</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span>
                 <span class="n">input_size</span><span class="p">,</span>
                 <span class="n">output_size</span><span class="p">,</span>
                 <span class="n">direction_option</span><span class="o">=</span><span class="s1">&#39;bi_sep&#39;</span><span class="p">,</span>
                 <span class="n">feat_drop</span><span class="o">=</span><span class="mf">0.</span><span class="p">,</span>
                 <span class="n">gcn_norm</span><span class="o">=</span><span class="s1">&#39;both&#39;</span><span class="p">,</span>
                 <span class="n">weight</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
                 <span class="n">bias</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
                 <span class="n">activation</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
                 <span class="n">allow_zero_in_degree</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
                 <span class="n">residual</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">GCNLayer</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">direction_option</span> <span class="o">==</span> <span class="s1">&#39;undirected&#39;</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">model</span> <span class="o">=</span> <span class="n">UndirectedGCNLayerConv</span><span class="p">(</span><span class="n">input_size</span><span class="p">,</span>
                                                <span class="n">output_size</span><span class="p">,</span>
                                                 <span class="n">feat_drop</span><span class="o">=</span><span class="n">feat_drop</span><span class="p">,</span>
                                                 <span class="n">gcn_norm</span><span class="o">=</span><span class="n">gcn_norm</span><span class="p">,</span>
                                                 <span class="n">weight</span><span class="o">=</span><span class="n">weight</span><span class="p">,</span>
                                                 <span class="n">bias</span><span class="o">=</span><span class="n">bias</span><span class="p">,</span>
                                                 <span class="n">activation</span><span class="o">=</span><span class="n">activation</span><span class="p">,</span>
                                                 <span class="n">allow_zero_in_degree</span><span class="o">=</span><span class="n">allow_zero_in_degree</span><span class="p">,</span>
                                                 <span class="n">residual</span><span class="o">=</span><span class="n">residual</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">direction_option</span> <span class="o">==</span> <span class="s1">&#39;bi_sep&#39;</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">model</span> <span class="o">=</span> <span class="n">BiSepGCNLayerConv</span><span class="p">(</span><span class="n">input_size</span><span class="p">,</span>
                                             <span class="n">output_size</span><span class="p">,</span>
                                             <span class="n">feat_drop</span><span class="o">=</span><span class="n">feat_drop</span><span class="p">,</span>
                                             <span class="n">gcn_norm</span><span class="o">=</span><span class="n">gcn_norm</span><span class="p">,</span>
                                             <span class="n">weight</span><span class="o">=</span><span class="n">weight</span><span class="p">,</span>
                                             <span class="n">bias</span><span class="o">=</span><span class="n">bias</span><span class="p">,</span>
                                             <span class="n">activation</span><span class="o">=</span><span class="n">activation</span><span class="p">,</span>
                                             <span class="n">allow_zero_in_degree</span><span class="o">=</span><span class="n">allow_zero_in_degree</span><span class="p">,</span>
                                             <span class="n">residual</span><span class="o">=</span><span class="n">residual</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">direction_option</span> <span class="o">==</span> <span class="s1">&#39;bi_fuse&#39;</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">model</span> <span class="o">=</span> <span class="n">BiFuseGCNLayerConv</span><span class="p">(</span><span class="n">input_size</span><span class="p">,</span>
                                             <span class="n">output_size</span><span class="p">,</span>
                                             <span class="n">feat_drop</span><span class="o">=</span><span class="n">feat_drop</span><span class="p">,</span>
                                             <span class="n">gcn_norm</span><span class="o">=</span><span class="n">gcn_norm</span><span class="p">,</span>
                                             <span class="n">weight</span><span class="o">=</span><span class="n">weight</span><span class="p">,</span>
                                             <span class="n">bias</span><span class="o">=</span><span class="n">bias</span><span class="p">,</span>
                                             <span class="n">activation</span><span class="o">=</span><span class="n">activation</span><span class="p">,</span>
                                             <span class="n">allow_zero_in_degree</span><span class="o">=</span><span class="n">allow_zero_in_degree</span><span class="p">,</span>
                                             <span class="n">residual</span><span class="o">=</span><span class="n">residual</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s1">&#39;Unknown `direction_option` value: </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">direction_option</span><span class="p">))</span>
</pre></div>
</div>
</div>
<div class="section" id="gcnlayerconv-construction-function">
<h2>4.1.3 GCNLayerConv Construction Function<a class="headerlink" href="#gcnlayerconv-construction-function" title="Permalink to this headline">¶</a></h2>
<p>We will take <code class="docutils literal notranslate"><span class="pre">BiSepGCNLayerConv</span></code> as an example. The construction function performs the following steps:</p>
<ol class="arabic simple">
<li><p>Set options.</p></li>
<li><p>Register learnable parameters.</p></li>
<li><p>Reset parameters.</p></li>
</ol>
<p>The aggregation and upate functions are formulated as:</p>
<div class="math notranslate nohighlight">
\[ \begin{align}\begin{aligned}h_{i, \vdash}^{(l+1)} = \sigma(b^{(l)}_{\vdash} + \sum_{j\in\mathcal{N}_{\vdash}(i)}\frac{1}{c_{ij}}h_{j, \vdash}^{(l)}W^{(l)}_{\vdash})\\h_{i, \dashv}^{(l+1)} = \sigma(b^{(l)}_{\dashv} + \sum_{j\in\mathcal{N}_{\dashv}(i)}\frac{1}{c_{ij}}h_{j, \dashv}^{(l)}W^{(l)}_{\dashv})\end{aligned}\end{align} \]</div>
<p>As shown in the equations, node embeddings in both directions are conveyed separately.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">BiSepGCNLayerConv</span><span class="p">(</span><span class="n">GNNLayerBase</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span>
                 <span class="n">input_size</span><span class="p">,</span>
                 <span class="n">output_size</span><span class="p">,</span>
                 <span class="n">feat_drop</span><span class="o">=</span><span class="mf">0.</span><span class="p">,</span>
                 <span class="n">gcn_norm</span><span class="o">=</span><span class="s1">&#39;both&#39;</span><span class="p">,</span>
                 <span class="n">weight</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
                 <span class="n">bias</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
                 <span class="n">activation</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
                 <span class="n">allow_zero_in_degree</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
                 <span class="n">residual</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">BiSepGCNLayerConv</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">gcn_norm</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">(</span><span class="s1">&#39;none&#39;</span><span class="p">,</span> <span class="s1">&#39;both&#39;</span><span class="p">,</span> <span class="s1">&#39;right&#39;</span><span class="p">):</span>
            <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s1">&#39;Invalid gcn_norm value. Must be either &quot;none&quot;, &quot;both&quot; or &quot;right&quot;.&#39;</span>
                               <span class="s1">&#39; But got &quot;</span><span class="si">{}</span><span class="s1">&quot;.&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">gcn_norm</span><span class="p">))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_input_size</span> <span class="o">=</span> <span class="n">input_size</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_output_size</span> <span class="o">=</span> <span class="n">output_size</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_gcn_norm</span> <span class="o">=</span> <span class="n">gcn_norm</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_allow_zero_in_degree</span> <span class="o">=</span> <span class="n">allow_zero_in_degree</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_feat_drop</span><span class="o">=</span><span class="n">nn</span><span class="o">.</span><span class="n">Dropout</span><span class="p">(</span><span class="n">feat_drop</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">weight</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">weight_fw</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Parameter</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">Tensor</span><span class="p">(</span><span class="n">input_size</span><span class="p">,</span> <span class="n">output_size</span><span class="p">))</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">weight_bw</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Parameter</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">Tensor</span><span class="p">(</span><span class="n">input_size</span><span class="p">,</span> <span class="n">output_size</span><span class="p">))</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">register_parameter</span><span class="p">(</span><span class="s1">&#39;weight_fw&#39;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">register_parameter</span><span class="p">(</span><span class="s1">&#39;weight_bw&#39;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">bias</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">bias_fw</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Parameter</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">Tensor</span><span class="p">(</span><span class="n">output_size</span><span class="p">))</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">bias_bw</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Parameter</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">Tensor</span><span class="p">(</span><span class="n">output_size</span><span class="p">))</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">register_parameter</span><span class="p">(</span><span class="s1">&#39;bias_fw&#39;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">register_parameter</span><span class="p">(</span><span class="s1">&#39;bias_bw&#39;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">residual</span><span class="p">:</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_input_size</span> <span class="o">!=</span> <span class="n">output_size</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">res_fc_fw</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Linear</span><span class="p">(</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_input_size</span><span class="p">,</span> <span class="n">output_size</span><span class="p">,</span> <span class="n">bias</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">res_fc_bw</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Linear</span><span class="p">(</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_input_size</span><span class="p">,</span> <span class="n">output_size</span><span class="p">,</span> <span class="n">bias</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">res_fc_fw</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">res_fc_bw</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">register_buffer</span><span class="p">(</span><span class="s1">&#39;res_fc_fw&#39;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">register_buffer</span><span class="p">(</span><span class="s1">&#39;res_fc_bw&#39;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">reset_parameters</span><span class="p">()</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">_activation</span> <span class="o">=</span> <span class="n">activation</span>
</pre></div>
</div>
<p>All learnable parameters and layers defined in this module are bidirectional, such as <code class="docutils literal notranslate"><span class="pre">self.weight_fw</span></code> and <code class="docutils literal notranslate"><span class="pre">self.weight_bw</span></code>.</p>
<p>Similarly, the aggregation and upate functions of <code class="docutils literal notranslate"><span class="pre">BiFuseGCNLayerConv</span></code> are formulated as:</p>
<div class="math notranslate nohighlight">
\[ \begin{align}\begin{aligned}h_{i, \vdash}^{(l+1)} = \sigma(b^{(l)}_{\vdash} + \sum_{j\in\mathcal{N}_{\vdash}(i)}\frac{1}{c_{ij}}h_{j}^{(l)}W^{(l)}_{\vdash})\\h_{i, \dashv}^{(l+1)} = \sigma(b^{(l)}_{\dashv} + \sum_{j\in\mathcal{N}_{\dashv}(i)}\frac{1}{c_{ij}}h_{j}^{(l)}W^{(l)}_{\dashv})\\r_{i}^{l} = \sigma (W_{f}[h_{i, \vdash}^{l};h_{i, \dashv}^{l};
        h_{i, \vdash}^{l}*h_{i, \dashv}^{l};
        h_{i, \vdash}^{l}-h_{i, \dashv}^{l}])\end{aligned}\end{align} \]</div>
<p>Node embeddings in both directions are fused in every layer. The construction code of <code class="docutils literal notranslate"><span class="pre">BiFuseGCNLayerConv</span></code> is as follows:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">BiFuseGCNLayerConv</span><span class="p">(</span><span class="n">GNNLayerBase</span><span class="p">):</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span>
                 <span class="n">input_size</span><span class="p">,</span>
                 <span class="n">output_size</span><span class="p">,</span>
                 <span class="n">feat_drop</span><span class="o">=</span><span class="mf">0.</span><span class="p">,</span>
                 <span class="n">gcn_norm</span><span class="o">=</span><span class="s1">&#39;both&#39;</span><span class="p">,</span>
                 <span class="n">weight</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
                 <span class="n">bias</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
                 <span class="n">activation</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
                 <span class="n">allow_zero_in_degree</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
                 <span class="n">residual</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">BiFuseGCNLayerConv</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">gcn_norm</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">(</span><span class="s1">&#39;none&#39;</span><span class="p">,</span> <span class="s1">&#39;both&#39;</span><span class="p">,</span> <span class="s1">&#39;right&#39;</span><span class="p">):</span>
            <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s1">&#39;Invalid gcn_norm value. Must be either &quot;none&quot;, &quot;both&quot; or &quot;right&quot;.&#39;</span>
                               <span class="s1">&#39; But got &quot;</span><span class="si">{}</span><span class="s1">&quot;.&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">gcn_norm</span><span class="p">))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_input_size</span> <span class="o">=</span> <span class="n">input_size</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_output_size</span> <span class="o">=</span> <span class="n">output_size</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_gcn_norm</span> <span class="o">=</span> <span class="n">gcn_norm</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_allow_zero_in_degree</span> <span class="o">=</span> <span class="n">allow_zero_in_degree</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_feat_drop</span><span class="o">=</span><span class="n">nn</span><span class="o">.</span><span class="n">Dropout</span><span class="p">(</span><span class="n">feat_drop</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">weight</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">weight_fw</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Parameter</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">Tensor</span><span class="p">(</span><span class="n">input_size</span><span class="p">,</span> <span class="n">output_size</span><span class="p">))</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">weight_bw</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Parameter</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">Tensor</span><span class="p">(</span><span class="n">input_size</span><span class="p">,</span> <span class="n">output_size</span><span class="p">))</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">register_parameter</span><span class="p">(</span><span class="s1">&#39;weight_fw&#39;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">register_parameter</span><span class="p">(</span><span class="s1">&#39;weight_bw&#39;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">bias</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">bias_fw</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Parameter</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">Tensor</span><span class="p">(</span><span class="n">output_size</span><span class="p">))</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">bias_bw</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Parameter</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">Tensor</span><span class="p">(</span><span class="n">output_size</span><span class="p">))</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">register_parameter</span><span class="p">(</span><span class="s1">&#39;bias_fw&#39;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">register_parameter</span><span class="p">(</span><span class="s1">&#39;bias_bw&#39;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">reset_parameters</span><span class="p">()</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">_activation</span> <span class="o">=</span> <span class="n">activation</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">fuse_linear</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Linear</span><span class="p">(</span><span class="mi">4</span> <span class="o">*</span> <span class="n">output_size</span><span class="p">,</span> <span class="n">output_size</span><span class="p">,</span> <span class="n">bias</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">residual</span><span class="p">:</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_input_size</span> <span class="o">!=</span> <span class="n">output_size</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">res_fc</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Linear</span><span class="p">(</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_input_size</span><span class="p">,</span> <span class="n">output_size</span><span class="p">,</span> <span class="n">bias</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">res_fc</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">register_buffer</span><span class="p">(</span><span class="s1">&#39;res_fc&#39;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="gcn-forward-function">
<h2>4.1.4 GCN Forward Function<a class="headerlink" href="#gcn-forward-function" title="Permalink to this headline">¶</a></h2>
<p>In NN module, <code class="docutils literal notranslate"><span class="pre">forward()</span></code> function does the actual message passing and computation. <code class="docutils literal notranslate"><span class="pre">forward()</span></code> takes a parameter <code class="docutils literal notranslate"><span class="pre">GraphData</span></code> as input.</p>
<p>The rest of the section takes a deep dive into the <code class="docutils literal notranslate"><span class="pre">forward()</span></code> function.</p>
<p>We first need to obatin the input graph node features and convert the <code class="docutils literal notranslate"><span class="pre">GraphData</span></code> to <code class="docutils literal notranslate"><span class="pre">dgl.DGLGraph</span></code>. Then, we need to determine whether to expand <code class="docutils literal notranslate"><span class="pre">feat</span></code> according to <code class="docutils literal notranslate"><span class="pre">self.use_edge_weight</span></code> and whether to use edge weight according to <code class="docutils literal notranslate"><span class="pre">self.direction_option</span></code>.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">feat</span> <span class="o">=</span> <span class="n">graph</span><span class="o">.</span><span class="n">node_features</span><span class="p">[</span><span class="s1">&#39;node_feat&#39;</span><span class="p">]</span>
<span class="n">dgl_graph</span> <span class="o">=</span> <span class="n">graph</span><span class="o">.</span><span class="n">to_dgl</span><span class="p">()</span>

<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">direction_option</span> <span class="o">==</span> <span class="s1">&#39;bi_sep&#39;</span><span class="p">:</span>
    <span class="n">h</span> <span class="o">=</span> <span class="p">[</span><span class="n">feat</span><span class="p">,</span> <span class="n">feat</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
    <span class="n">h</span> <span class="o">=</span> <span class="n">feat</span>

<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">use_edge_weight</span><span class="p">:</span>
    <span class="n">edge_weight</span> <span class="o">=</span> <span class="n">graph</span><span class="o">.</span><span class="n">edge_features</span><span class="p">[</span><span class="s1">&#39;edge_weight&#39;</span><span class="p">]</span>
    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">direction_option</span> <span class="o">!=</span> <span class="s1">&#39;undirected&#39;</span><span class="p">:</span>
        <span class="n">reverse_edge_weight</span> <span class="o">=</span> <span class="n">graph</span><span class="o">.</span><span class="n">edge_features</span><span class="p">[</span><span class="s1">&#39;reverse_edge_weight&#39;</span><span class="p">]</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">reverse_edge_weight</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">else</span><span class="p">:</span>
    <span class="n">edge_weight</span> <span class="o">=</span> <span class="kc">None</span>
    <span class="n">reverse_edge_weight</span> <span class="o">=</span> <span class="kc">None</span>
</pre></div>
</div>
<p>The following code actually performs message passing and feature updating.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">num_layers</span> <span class="o">-</span> <span class="mi">1</span><span class="p">):</span>
    <span class="n">h</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">gcn_layers</span><span class="p">[</span><span class="n">l</span><span class="p">](</span><span class="n">dgl_graph</span><span class="p">,</span> <span class="n">h</span><span class="p">,</span> <span class="n">edge_weight</span><span class="o">=</span><span class="n">edge_weight</span><span class="p">,</span> <span class="n">reverse_edge_weight</span><span class="o">=</span><span class="n">reverse_edge_weight</span><span class="p">)</span>
    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">direction_option</span> <span class="o">==</span> <span class="s1">&#39;bi_sep&#39;</span><span class="p">:</span>
        <span class="n">h</span> <span class="o">=</span> <span class="p">[</span><span class="n">each</span><span class="o">.</span><span class="n">flatten</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">for</span> <span class="n">each</span> <span class="ow">in</span> <span class="n">h</span><span class="p">]</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">h</span> <span class="o">=</span> <span class="n">h</span><span class="o">.</span><span class="n">flatten</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

<span class="n">logits</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">gcn_layers</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">](</span><span class="n">dgl_graph</span><span class="p">,</span> <span class="n">h</span><span class="p">)</span>

<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">direction_option</span> <span class="o">==</span> <span class="s1">&#39;bi_sep&#39;</span><span class="p">:</span>
    <span class="n">logits</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">cat</span><span class="p">(</span><span class="n">logits</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
    <span class="k">pass</span>

<span class="n">graph</span><span class="o">.</span><span class="n">node_features</span><span class="p">[</span><span class="s1">&#39;node_emb&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">logits</span>
</pre></div>
</div>
</div>
</div>


           </div>
          </div>
          <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
        <a href="../gnn.html" class="btn btn-neutral float-left" title="Chapter 4. Graph Encoder" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
        <a href="ggnn.html" class="btn btn-neutral float-right" title="Gated Graph Neural Networks" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
    </div>

  <hr/>

  <div role="contentinfo">
    <p>&#169; Copyright 2020, Graph4AI Group.</p>
  </div>

  Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
    <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
    provided by <a href="https://readthedocs.org">Read the Docs</a>.
   

</footer>
        </div>
      </div>
    </section>
  </div>
  <script>
      jQuery(function () {
          SphinxRtdTheme.Navigation.enable(true);
      });
  </script> 

</body>
</html>